package parsing;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit.ParserCallback;

import com.smartxls.WorkBook;

public class CustomGenomeParser extends ParserCallback {

	private String domaine;
	private Genome genome;
	private WorkBook wb;
	private WorkBook wb_m;
	private WorkBook wbError;

	private int countTable = 0; // Nombre de <table> inclu l'un dans l'autre
	// Flag pour indiquer qu'on veut le prochain Text qu'on trouvera
	private boolean theNextTextIsTheARN = false; 
	
	private static Pattern patternArn;
	private static Pattern patternAnticodon;
	private static Pattern patternSeq;
	
	public CustomGenomeParser(String domaine, Genome genome, WorkBook wb, WorkBook wb_m, WorkBook wbError) {
		this.domaine = domaine;
		this.genome = genome;
		this.wb = wb;
		this.wb_m = wb_m;
		this.wbError = wbError;
	}
	
	/** Permet de créer les patterns, à appeler avant l'utilisation du parseur */
	public static void init() {
		// \\S : tout sauf blancs, \\s : blancs, \\d décimal
		String patternStr = "(\\S*)\\s*\\S*\\s*Length:\\s*(\\d*)\\s*bp\n"
			+ "Type:\\s*(\\S*)\\s*Anticodon:\\s*(\\S{3})\\s*at\\s*(\\d*)-(\\d*)\\s*\\S*\\s*Score:\\s*(\\d*\\.\\d*)\n\\s*"
			+ "(Possible intron:\\s*\\S*\\s*\\S*\\s*)?"
			+ "Seq:\\s*(\\S*)\\s*"
			+ "Str:\\s*([>.<]*)\\s*" 
			+ "(BHB:\\s*\\S*\\s*)?";

		patternArn = Pattern.compile(patternStr);
		
		patternAnticodon = Pattern.compile("[ACGT]{3}");
		patternSeq = Pattern.compile("[ACGT]*");
	}

	/** Exécuté lorsqu'il y a du texte
	 * @see javax.swing.text.html.HTMLEditorKit.ParserCallback#handleText(char[], int)
	 */
	public void handleText(char[] data, int pos) {
		if (countTable > 0 && theNextTextIsTheARN) {
			theNextTextIsTheARN = false;
			
			String ARN = new String(data);
			if (ARN.length() > 10) {
				// System.out.println("{"+ARN+"}");
				traiteARN(ARN); // Traitement de l'ARN
			}
		}
	}

	/** Exécuté au début d'une balise
	 * @see javax.swing.text.html.HTMLEditorKit.ParserCallback#handleStartTag(javax.swing.text.html.HTML.Tag, javax.swing.text.MutableAttributeSet, int)
	 */
	public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
		if (t.equals(HTML.Tag.PRE)) {
			theNextTextIsTheARN = true;
		}
		if (t.equals(HTML.Tag.TABLE)) {
			// J'incremte les <table> qui sont un dans l'autre
			countTable++;
		}
	}

	/** Exécuté à la fin d'une balise
	 * @see javax.swing.text.html.HTMLEditorKit.ParserCallback#handleEndTag(javax.swing.text.html.HTML.Tag, int)
	 */
	public void handleEndTag(HTML.Tag t, int pos) {
		if (t.equals(HTML.Tag.TABLE)) {
			// Je décremente les <table> qui sont un dans l'autre
			countTable--;
		}
	}

	/* Exemple d'arn :
	 * chr6.trna18 (30577523-30577595) Length: 73 bp Type: Ala Anticodon: AGC at
	 * 34-36 (30577556-30577558) Score: 58.03 Seq:
	 * GGGGATGTGGCTCAGATGGTAGAGCGCTCGCTTAGCATGTGAGAGGtACGGGGATCGATACCCCGCATCTACA
	 * Str:
	 * >.>>>>>..>>>>........<<<<.>>>>>.......<<<<<.....>>>>>.......<<<<<<<<<<.<.
	 */
	/**
	 * Vérifie que la description de l'arn est correcte, écrit dans le fichier si c'est le cas
	 */
	private void traiteARN(String arn) {
		String msgErreur = null;
		String identifiant = "";
		
		//On regarde si la structure est correct
		Matcher matcher = patternArn.matcher(arn);
		boolean matchFound = matcher.matches();

		if (!matchFound) {
			Main.log("L'arn n'a pas été bien reconnu  : \n" + arn, true);
			msgErreur = "L'arn n'a pas été bien reconnu";
		} else {
			
			//On récupere les données dans la chaîne (les groupes sont délimités par les paranthèses)
			// 1:identifiant;  2:longueur;  3:type;  4:anticodon
			// 5:début de l'anticodon;  6:fin anticodon;  7:score
			// 8:possible intron
			// 9:séquence;  10:Str; 11:BHB
			identifiant = matcher.group(1);
			int longueur = Integer.parseInt(matcher.group(2));
			int debutAnticodon = Integer.parseInt(matcher.group(5));
			double score = Double.parseDouble(matcher.group(7));
			String seq = matcher.group(9).toUpperCase();
			
			//On regarde si l'anticodon est bien constitué de ACGT (pas de '?')
			if (!patternAnticodon.matcher(matcher.group(4)).matches()) {
				Main.log("L'anticodon de l'arn " + matcher.group(1) + " n'est pas renseigné.", true);
				msgErreur = "L'anticodon n'est pas renseigné.";
				
			//On regarde si la séquence est bien constitué de ACGT
			} else if (!patternSeq.matcher(seq).matches()) {
				Main.log("La séquence de l'arn " + matcher.group(1) + " contient des lettres non permises.", true);
				msgErreur = "La séquence contient des lettres non permises";
			} else {
				try {
					
					//On vérifie si l'anticodon est bien à la place indiquée
					if (!seq.subSequence(debutAnticodon - 1, debutAnticodon + 2).equals(matcher.group(4))) {
						Main.log("L'anticodon de l'arn " + matcher.group(1) + " n'est pas à l'endroit indiqué.", true);
						msgErreur = "L'anticodon n'est pas à l'endroit indiqué.";
					}
					else {
						//C'est bon l'arn semble correct
						//TODO Déplacer dans une classe héritant de Workbook
						int lr = wb.getLastRow()+1;
						wb.setNumber(lr, 0, lr);
						wb.setText(lr, 1, genome.getFamille());
						wb.setText(lr, 2, genome.getNom());
						wb.setText(lr, 3, matcher.group(1));
						wb.setNumber(lr, 4, longueur);
						wb.setText(lr, 5, matcher.group(3));
						wb.setText(lr, 6, matcher.group(4));
						wb.setNumber(lr, 7, debutAnticodon);
						wb.setText(lr, 8, seq);
						wb.setText(lr, 9, matcher.group(10));
						wb.setNumber(lr, 10, score);
						
						
						
						lr = wb_m.getLastRow()+1;
						wb_m.setNumber(lr, 0, lr);
						wb_m.setText(lr, 1, genome.getFamille());
						wb_m.setText(lr, 2, genome.getNom());
						wb_m.setText(lr, 3, matcher.group(1));
						wb_m.setNumber(lr, 4, longueur);
						wb_m.setText(lr, 5, matcher.group(3));
						wb_m.setText(lr, 6, matcher.group(4));
						wb_m.setNumber(lr, 7, debutAnticodon);
						wb_m.setText(lr, 8, seq);
						wb_m.setText(lr, 9, matcher.group(10));
						wb_m.setNumber(lr, 10, score);
					}

				} catch (NumberFormatException e) {
					Main.log("L'arn " + matcher.group(1) + " a un nombre mal formé.", true);
					msgErreur = "L'arn a un nombre mal formé.";
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		// Gestion des erreurs
		if (msgErreur != null) {
			int lr = wbError.getLastRow()+1;
			try {
				wbError.setNumber(lr, 0, lr);
				wbError.setText(lr, 1, this.domaine);
				wbError.setText(lr, 2, genome.getFamille());
				wbError.setText(lr, 3, genome.getNom());
				wbError.setText(lr, 4, identifiant);
				wbError.setText(lr, 5, msgErreur);
				wbError.setText(lr, 6, arn);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}